﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.XPath;

namespace Facebook.Api
{
    public static class FacebookObjectExtensions
    {
        public static T GetValueType<T>(this IFacebookObject obj, String xpath)
            where T : struct
        {
            if (obj.InnerDictionary.ContainsKey(xpath)) return (T)obj.InnerDictionary[xpath];
            else if (obj.XmlContent == null) return default(T);
            else
            {
                var element = obj.XmlContent.XPathSelectElement("//" + xpath);
                T result = default(T);
                if (element != null) result = (T)Convert.ChangeType(element.Value, typeof(T));
                obj.InnerDictionary.Add(xpath, result);
                return result;
            }
        }

        public static String GetString(this IFacebookObject obj, String xpath)
        {
            if (obj.InnerDictionary.ContainsKey(xpath)) return (String)obj.InnerDictionary[xpath];
            else if (obj.XmlContent == null) return null;
            else
            {
                var element = obj.XmlContent.XPathSelectElement("//" + xpath);
                String result = null;
                if (element != null) result = element.Value;
                obj.InnerDictionary.Add(xpath, result);
                return result;
            }
        }

        public static T GetFacebookObject<T>(this IFacebookObject obj, String xpath)
            where T : FacebookObjectBase, new()
        {
            if (obj.InnerDictionary.ContainsKey(xpath)) return (T)obj.InnerDictionary[xpath];
            else if (obj.XmlContent == null) return default(T);
            else
            {
                var element = obj.XmlContent.XPathSelectElement("//" + xpath);
                T result = null;
                if (element != null)
                {
                    result = new T();
                    result.Init(element);
                }
                obj.InnerDictionary.Add(xpath, result);
                return result;
            }
        }

        public static FacebookList<T> GetFacebookObjectCollection<T>(this IFacebookObject obj, String xpath)
            where T : FacebookObjectBase, new()
        {
            if (obj.InnerDictionary.ContainsKey(xpath)) return (FacebookList<T>)obj.InnerDictionary[xpath];
            else if (obj.XmlContent == null) return null;
            else
            {
                var element = obj.XmlContent.XPathSelectElement("//" + xpath);
                var attr = (FacebookObjectAttribute)typeof(T).GetCustomAttributes(typeof(FacebookObjectAttribute), true)[0];
                FacebookList<T> result = null;
                if (element != null) result = new FacebookList<T>(element, attr.XPath);
                obj.InnerDictionary.Add(xpath, result);
                return result;
            }
        }

        public static List<T> GetValueTypeCollection<T>(this IFacebookObject obj, String xpath, String itemXPath)
            where T : struct
        {
            if (obj.InnerDictionary.ContainsKey(xpath)) return (List<T>)obj.InnerDictionary[xpath];
            else if (obj.XmlContent == null) return null;
            else
            {
                var elements = obj.XmlContent.XPathSelectElements("//" + itemXPath);
                var values = elements.Select(element => (T)Convert.ChangeType(element.Value, typeof(T)));
                List<T> result = null;
                if (elements != null) result = new List<T>(values);
                obj.InnerDictionary.Add(xpath, result);
                return result;
            }
        }

        public static List<String> GetStringCollection(this IFacebookObject obj, String xpath, String itemXPath)
        {
            if (obj.InnerDictionary.ContainsKey(xpath)) return (List<String>)obj.InnerDictionary[xpath];
            else if (obj.XmlContent == null) return null;
            else
            {
                var elements = obj.XmlContent.XPathSelectElements("//" + itemXPath);
                List<String> result = null;
                if (elements != null)
                {
                    var values = elements.Select(element => element.Value);
                    result = new List<String>(values);
                }
                obj.InnerDictionary.Add(xpath, result);
                return result;
            }
        }
    }
}
